package config

import (
	"context"

	"github.com/glennliao/apijson-go/consts"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/samber/lo"
)

type T条件请求 struct {
	F访问名称    string // _access 中的alias
	B表访问角色列表 []string
	Q请求方法    string
	J节点请求数据  g.Map  // 节点的请求数据
	J节点角色    string // 节点的角色
}

type M访问条件函数 func(ctx context.Context, req T条件请求, condition *T条件结果) error

type M角色请求 struct {
	F访问名称 string
	Q请求方法 string
	J节点角色 string // 前端传入的节点的角色, 目前未传入则为空
}

type M默认角色函数 func(ctx context.Context, req M角色请求) (string, error)

func M默认角色(ctx context.Context, req M角色请求) (string, error) {
	return consts.W未登录用户, nil
}

func M默认条件(ctx context.Context, req T条件请求, condition *T条件结果) error {
	return nil
}

type F访问控制 struct {
	// 禁用_access权限校验, 默认为false, 需手动开启
	J禁用验证 bool

	// 用于 根据accessName+user来自定义添加sql条件, 完成数据的权限限制
	T条件处理函数 M访问条件函数

	// nodeRole 为前端显式指定的role, 需要此函数中判断该role是不是用户角色之一, 返回最终该节点的角色
	M默认角色函数 M默认角色函数

	J角色列表 []string

	F访问配置映射 map[string]F访问配置结构
}

func X新建访问控制() *F访问控制 {
	// fixme 统一access字段名大小写问题
	// fixme
	实例 := &F访问控制{}
	实例.T条件处理函数 = M默认条件
	实例.M默认角色函数 = M默认角色
	实例.J角色列表 = []string{consts.W未登录用户, consts.D登录用户, consts.S数据拥有者, consts.G管理员}

	return 实例
}

// 添加角色 添加应用中额外的角色
func (控制 *F访问控制) T添加角色(角色列表 []string) *F访问控制 {
	for _, 角色 := range 角色列表 {
		if !lo.Contains(控制.J角色列表, 角色) {
			控制.J角色列表 = append(控制.J角色列表, 角色)
		}
	}
	return 控制
}

func (控制 *F访问控制) H获取角色列表() []string { return 控制.J角色列表 }
